package main

import (
	"database/sql"
	"fmt"
	"github.com/spf13/cobra"
	"github.com/spf13/viper"
	"io/ioutil"
	"iot/common/sys"
	"os"
	"os/exec"
	"path/filepath"
	"runtime"
	"strconv"
	"strings"
	"syscall"
	"time"
)

func addInitCommands() {
	initCmd := &cobra.Command{
		Use:   "init",
		Short: "平台初始化操作",
	}

	initDbCmd := &cobra.Command{
		Use:   "db [配置路径]",
		Short: "初始化数据库",
		Args:  cobra.MaximumNArgs(0),
		Run: func(cmd *cobra.Command, args []string) {
			fmt.Printf("正在初始化数据库……\n")

			if err := initDatabase(); err != nil {
				fmt.Printf("❌ 数据库初始化失败: %v\n", err)
				return
			}
		},
	}

	// 初始化平台
	initPlatformCmd := &cobra.Command{
		Use:   "platform",
		Short: "初始化平台服务",
		Run: func(cmd *cobra.Command, args []string) {
			ctx := getContext(cmd)

			if ctx.Verbose {
				fmt.Println("正在初始化平台服务...")
			}

			if err := initPlatform(); err != nil {
				fmt.Printf("❌ 平台初始化失败: %v\n", err)
				return
			}

			fmt.Println("✅ 平台初始化完成")
		},
	}

	// 关闭平台
	shutdownCmd := &cobra.Command{
		Use:   "shutdown",
		Short: "安全关闭平台",
		Run: func(cmd *cobra.Command, args []string) {
			ctx := getContext(cmd)

			if ctx.Verbose {
				fmt.Println("正在关闭平台...")
			}

			if err := shutdownPlatform(); err != nil {
				fmt.Printf("❌ 关闭失败: %v\n", err)
				return
			}

			fmt.Println("✅ 平台已安全关闭")
		},
	}

	// 重新初始化平台
	reinitCmd := &cobra.Command{
		Use:   "reinit",
		Short: "重新初始化平台",
		Long:  "关闭当前平台并重新初始化所有服务",
		Run: func(cmd *cobra.Command, args []string) {
			ctx := getContext(cmd)

			if ctx.Verbose {
				fmt.Println("开始重新初始化平台...")
			}

			// 1. 关闭平台
			if err := shutdownPlatform(); err != nil {
				fmt.Printf("❌ 关闭失败: %v\n", err)
				return
			}

			// 2. 初始化平台
			if err := initPlatform(); err != nil {
				fmt.Printf("❌ 初始化失败: %v\n", err)
				return
			}

			fmt.Println("✅ 平台已成功重新初始化")
		},
	}

	// 添加命令到命令组
	initCmd.AddCommand(initDbCmd, initPlatformCmd, shutdownCmd, reinitCmd)
	RootCmd.AddCommand(initCmd)
}

// initPlatform 初始化平台主服务
func initPlatform() error {
	const platformExe = "platform" // 在Linux/Mac上的可执行文件名
	platformName := platformExe

	// 根据操作系统确定正确的可执行文件名
	if runtime.GOOS == "windows" {
		platformName = platformExe + ".exe"
	}

	// 1. 检查平台进程是否已运行
	running, pid, err := isProcessRunning(platformName)
	if err != nil {
		return fmt.Errorf("检查进程状态失败: %w", err)
	}

	// 2. 如果进程已运行，终止它
	if running {
		fmt.Printf("发现正在运行的 %s 进程 (PID: %d)，准备终止...\n", platformName, pid)

		if err := killProcess(pid); err != nil {
			return fmt.Errorf("终止进程失败: %w", err)
		}

		// 等待进程退出
		fmt.Println("等待进程完全退出...")
		time.Sleep(2 * time.Second)
	}

	// 3. 启动新进程
	fmt.Printf("正在启动 %s 服务...\n", platformName)
	return startPlatform(platformName)
}

// isProcessRunning 检查进程是否在运行
func isProcessRunning(processName string) (bool, int, error) {
	switch runtime.GOOS {
	case "windows":
		return checkWindowsProcess(processName)
	default: // Linux, MacOS
		return checkUnixProcess(processName)
	}
}

// checkWindowsProcess 检查Windows进程
func checkWindowsProcess(processName string) (bool, int, error) {
	// 执行 tasklist 命令
	cmd := exec.Command("tasklist", "/FI", "IMAGENAME eq "+processName, "/FO", "CSV", "/NH")
	output, err := cmd.Output()
	if err != nil {
		return false, 0, err
	}

	// 解析输出
	lines := strings.Split(string(output), "\n")
	for _, line := range lines {
		// 过滤空行
		if strings.TrimSpace(line) == "" {
			continue
		}

		// 拆解CSV格式
		parts := strings.Split(line, ",")
		if len(parts) < 2 {
			continue
		}

		// 提取PID
		name := strings.Trim(parts[0], `" `)
		if name != processName {
			continue
		}

		// 解析PID
		pidStr := strings.Trim(parts[1], `" `)
		pid, err := strconv.Atoi(pidStr)
		if err != nil {
			continue
		}

		return true, pid, nil
	}

	return false, 0, nil
}

// checkUnixProcess 检查Unix进程
func checkUnixProcess(processName string) (bool, int, error) {
	// 检查 /proc 目录
	files, err := ioutil.ReadDir("/proc")
	if err != nil {
		// 如果无法读取 /proc，尝试使用 ps 命令
		return checkUnixProcessWithPS(processName)
	}

	for _, file := range files {
		if !file.IsDir() {
			continue
		}

		// 检查是否数字目录（进程）
		pid, err := strconv.Atoi(file.Name())
		if err != nil {
			continue
		}

		// 检查进程状态
		statusFile := filepath.Join("/proc", file.Name(), "status")
		content, err := ioutil.ReadFile(statusFile)
		if err != nil {
			continue
		}

		// 解析进程状态
		for _, line := range strings.Split(string(content), "\n") {
			if strings.HasPrefix(line, "Name:") {
				fields := strings.Fields(line)
				if len(fields) < 2 {
					continue
				}

				name := fields[1]
				if name == processName {
					return true, pid, nil
				}
			}
		}
	}

	return false, 0, nil
}

// checkUnixProcessWithPS 使用 ps 命令检查进程
func checkUnixProcessWithPS(processName string) (bool, int, error) {
	// 执行 ps 命令
	cmd := exec.Command("ps", "-A", "-o", "pid,comm")
	output, err := cmd.Output()
	if err != nil {
		return false, 0, err
	}

	// 解析输出
	lines := strings.Split(string(output), "\n")
	for _, line := range lines {
		fields := strings.Fields(line)
		if len(fields) < 2 {
			continue
		}

		// 解析PID和进程名
		pid, err := strconv.Atoi(fields[0])
		if err != nil {
			continue
		}

		if fields[1] == processName {
			return true, pid, nil
		}
	}

	return false, 0, nil
}

// killProcess 终止进程
func killProcess(pid int) error {
	process, err := os.FindProcess(pid)
	if err != nil {
		return err
	}

	// 尝试优雅终止
	err = process.Signal(syscall.SIGTERM)
	if err != nil {
		// 如果优雅终止失败，强制终止
		return process.Kill()
	}

	// 等待一段时间让进程退出
	wait := make(chan error, 1)
	go func() {
		_, err := process.Wait()
		wait <- err
	}()

	select {
	case <-wait:
		return nil
	case <-time.After(5 * time.Second):
		// 如果超时，强制终止
		return process.Kill()
	}
}

// startPlatform 启动平台服务
func startPlatform(platformExe string) error {
	// 获取当前可执行文件路径
	exe, err := os.Executable()
	if err != nil {
		return fmt.Errorf("获取可执行文件路径失败: %w", err)
	}

	// 构造平台可执行文件路径
	dir := filepath.Dir(exe)
	platformPath := filepath.Join(dir, platformExe)

	// 检查文件是否存在
	if _, err := os.Stat(platformPath); os.IsNotExist(err) {
		return fmt.Errorf("未找到平台可执行文件: %s", platformPath)
	}

	// 准备启动命令
	cmd := exec.Command(platformPath)

	// 设置工作目录
	cmd.Dir = dir

	// 重定向输出（否则会继承当前进程的IO）
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr

	// 启动进程
	if err := cmd.Start(); err != nil {
		return fmt.Errorf("启动进程失败: %w", err)
	}

	// 记录启动日志
	fmt.Printf("平台服务已启动 (PID: %d)\n", cmd.Process.Pid)

	// 不要等待进程结束（后台运行）
	go func() {
		if err := cmd.Wait(); err != nil {
			fmt.Printf("平台服务异常退出: %v\n", err)
		} else {
			fmt.Println("平台服务正常退出")
		}
	}()

	return nil
}

func shutdownPlatform() error {
	// 这里实现平台关闭逻辑
	fmt.Println("执行平台关闭")
	return nil
}

func initDatabase() error {
	// 获取数据库文件和SQL脚本路径
	dbPath := filepath.Join(sys.RootPath(), "config", viper.GetString("tools.db"))
	sqlScriptPath := filepath.Join(sys.RootPath(), "config", viper.GetString("tools.sql"))

	// 确保数据库目录存在
	dbDir := filepath.Dir(dbPath)
	if err := os.MkdirAll(dbDir, 0755); err != nil {
		return fmt.Errorf("创建数据库目录失败: %w", err)
	}

	// 读取 SQL 脚本文件
	sqlScript, err := os.ReadFile(sqlScriptPath)
	if err != nil {
		return fmt.Errorf("读取SQL脚本失败: %w", err)
	}

	// 连接到SQLite数据库
	db, err := sql.Open("sqlite", dbPath)
	if err != nil {
		return fmt.Errorf("连接数据库失败: %w", err)
	}
	defer db.Close()

	// 开启事务
	tx, err := db.Begin()
	if err != nil {
		return fmt.Errorf("开启事务失败: %w", err)
	}

	// 执行SQL脚本
	if _, err := tx.Exec(string(sqlScript)); err != nil {
		_ = tx.Rollback()
		return fmt.Errorf("执行SQL脚本失败: %w", err)
	}

	// 提交事务
	if err := tx.Commit(); err != nil {
		return fmt.Errorf("提交事务失败: %w", err)
	}

	fmt.Printf("✅ 数据库初始化成功! 创建/更新数据库文件: %s\n", dbPath)
	return nil
}
